#pragma once
#include <utility>// for std::forward, std::decay_t

#define Tuple CTuple

template <typename A, typename B, typename C>
class CTuple {
public:
	CTuple() = default;

	// perfect forwarding constructor (supports move semantics and avoids copying)
	template <typename T1, typename T2, typename T3>
	CTuple(T1&& a, T2&& b, T3&& c) : first(std::forward<T1>(a)), second(std::forward<T2>(b)), third(std::forward<T3>(c)) {}

	A first;
	B second;
	C third;
};

template <typename T1, typename T2, typename T3>
CTuple<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>> MakeTuple(T1&& a, T2&& b, T3&& c) {
	return CTuple<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>(
		std::forward<T1>(a),
		std::forward<T2>(b),
		std::forward<T2>(c)
	);
}

/**@brief C++17 `CTAD`: Class Template Argument Deduction */
template <typename T1, typename T2, typename T3>
CTuple(T1&& a, T2&& b, T3&& c) -> CTuple<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>;